#include "ResourcesManager.h"
#include "FileManager.h"
#include <string.h>
#include "Model.h"
#include "Texture.h"
#include "Shader.h"

//---------------------------------------------------
/// Constructor
//---------------------------------------------------
ResourcesManager::ResourcesManager(void)
{
	m_models = 0;
	m_textures = 0;
	m_shaders = 0;

	m_numOfModels = 0;
	m_numOfTextures = 0;
	m_numOfShaders = 0;
}

//---------------------------------------------------
/// Init
//---------------------------------------------------
void ResourcesManager::Init(const char* file)
{
	FILE* f = FileManager::GetInstance()->Open(file, "r");

	if (f == NULL)
	{
		LOGE("Can't not open Resource Manager file\n");
		return;
	}

	char id[MAX];
	char path[100];	// is also pathVS
	char wrap[8];
	char pathFS[100];
	char state[10];
	int N, M;

	// MODELS
	fscanf(f, "#Model: %d\n", &N);
	m_numOfModels = N;
	m_models = new Model* [m_numOfModels];
	fscanf(f, "%*s %*s\n");
	for(int i = 0; i < m_numOfModels; ++i)
	{
		fscanf(f, "%s %s\n", id, path);
		m_models[i] = new Model();
		m_models[i]->Init(path, id);
	}

	// TEXTURES
	fscanf(f, "#Texture: %d\n", &N);
	m_numOfTextures = N;
	m_textures = new Texture* [m_numOfTextures];

	fscanf(f, "%*s %*s %*s\n");
	// Texture2D
	fscanf(f, "Texture2D: %d\n", &N);
	for(int i = 0; i < N; ++i)
	{
		fscanf(f, "%s %s %s\n", id, path, wrap);
		m_textures[i] = new Texture();
		if(strcmp(wrap, "REPEAT") == 0)
		{
			m_textures[i]->Init(path, id, GL_TEXTURE_2D, GL_REPEAT);
		}
		else if(strcmp(wrap, "CLAMP") == 0)
		{
			m_textures[i]->Init(path, id, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE);
		}
		else if(strcmp(wrap, "MR_REP") == 0)
		{
			m_textures[i]->Init(path, id, GL_TEXTURE_2D, GL_MIRRORED_REPEAT);
		}
		else
		{
			LOGE("ERROR: unexpect value of WRAP_MODE (please check ResourcesManager.txt)\n");
		}
	}
	// TextureCube
	fscanf(f, "TextureCube: %d\n", &M);
	for(int i = 0; i < M; ++i)
	{
		fscanf(f, "%s %s %s\n", id, path, wrap);
		m_textures[i + N] = new Texture();
		if(strcmp(wrap, "REPEAT") == 0)
		{
			m_textures[i + N]->Init(path, id, GL_TEXTURE_CUBE_MAP, GL_REPEAT);
		}
		else if(strcmp(wrap, "CLAMP") == 0)
		{
			m_textures[i + N]->Init(path, id, GL_TEXTURE_CUBE_MAP, GL_CLAMP_TO_EDGE);
		}
		else if(strcmp(wrap, "MR_REP") == 0)
		{
			m_textures[i + N]->Init(path, id, GL_TEXTURE_CUBE_MAP, GL_MIRRORED_REPEAT);
		}
		else
		{
			LOGE("ERROR: unexpect value of WRAP_MODE (please check ResourcesManager.txt)\n");
		}	
	}

	// SHADERS
	fscanf(f, "#Shader: %d\n", &N);
	m_numOfShaders = N;
	m_shaders = new Shader* [m_numOfShaders];
	fscanf(f, "%*s %*s %*s %*s\n");

	for(int i = 0; i < m_numOfShaders; ++i)
	{
		fscanf(f, "%s %s %s", id, path, pathFS);
		m_shaders[i] = new Shader();
		m_shaders[i]->Init(id, path, pathFS);

		fscanf(f, "%d: ", &M);
		for(int j = 0; j < M; j++)
		{
			fscanf(f, "%s", state);
			if(strcmp(state, "CULL") == 0)
			{
				m_shaders[i]->AddState(GL_CULL_FACE);
			}
			else if(strcmp(state, "DEPTH") == 0)
			{
				m_shaders[i]->AddState(GL_DEPTH_TEST);
			}
			else if(strcmp(state, "BLEND") == 0)
			{
				m_shaders[i]->AddState(GL_BLEND);
			}
			else
			{
				LOGE("ERROR: unexpect value of Shader's state (please check ResourcesManager.txt)\n");
			}	
		}

		fscanf(f, "\n");
	}

	fclose(f);
}

//---------------------------------------------------
/// Get Model by id
//---------------------------------------------------
Model* ResourcesManager::GetModelById(const char* id)
{
	Model* model = NULL;
	for(int i = 0; i < m_numOfModels; ++i)
	{
		if(strcmp(m_models[i]->GetId(), id) == 0)
		{
			model = m_models[i];
			break;
		}
	}

	return model;
}

//---------------------------------------------------
/// Get Texture by id
//---------------------------------------------------
Texture* ResourcesManager::GetTextureById(const char* id)
{
	Texture* texture = NULL;
	for(int i = 0; i < m_numOfTextures; ++i)
	{
		if(strcmp(m_textures[i]->GetId(), id) == 0)
		{
			texture = m_textures[i];
			break;
		}
	}

	return texture;
}

//---------------------------------------------------
/// Get Shader by id
//---------------------------------------------------
Shader* ResourcesManager::GetShaderById(const char* id)
{
	Shader* shader = NULL;
	for(int i = 0; i < m_numOfShaders; ++i)
	{
		if(strcmp(m_shaders[i]->GetId(), id) == 0)
		{
			shader = m_shaders[i];
			break;
		}
	}

	return shader;
}

//---------------------------------------------------
/// Get Instance
//---------------------------------------------------
ResourcesManager* ResourcesManager::s_Instance = 0;
ResourcesManager* ResourcesManager::GetInstance()
{
	if (!s_Instance)
	{
		s_Instance = new ResourcesManager();
	}
	return s_Instance;
}

//---------------------------------------------------
/// Destroy Instance
//---------------------------------------------------
void ResourcesManager::Destroy() 
{
	if (s_Instance)
	{
		delete s_Instance;
		s_Instance = NULL;
	}
}

//---------------------------------------------------
/// Destructor
//---------------------------------------------------
ResourcesManager::~ResourcesManager(void)
{
	for(int i = 0; i < m_numOfModels; ++i)
	{
		SAFE_DEL(m_models[i]);
	}
	SAFE_DEL_ARRAY(m_models);

	for(int i = 0; i < m_numOfTextures; ++i)
	{
		SAFE_DEL(m_textures[i]);
	}
	SAFE_DEL_ARRAY(m_textures);

	for(int i = 0; i < m_numOfShaders; ++i)
	{
		SAFE_DEL(m_shaders[i]);
	}
	SAFE_DEL_ARRAY(m_shaders);
}
